#ifndef __Q__WEAK__PTR__HH__
#define __Q__WEAK__PTR__HH__

#include <vector>
#include <iostream>
#include <string>
#include "QEnvPrereqs.h"
#include "QEnvStatus.h"

template<typename ItemType> class WeakPtr;

template<typename ItemType>
class WeakPtr
{
public:
	typename typedef ItemType Item;

protected:
	bool kill;
	Item * d;

public:
	WeakPtr( Item * ptr = NULL, bool destroy = false ) : d(ptr), kill(destroy)
	{
#if defined(_DEBUG)||!defined(NDEBUG)
		if( d ) QEnvStatus::addMessage( "Creating "+getName(), true );
		else QEnvStatus::addMessage( "Creating "+getName()+" : NULL", true );
#endif
	}
	WeakPtr( const WeakPtr<Item>& hdr ) : d(hdr.d), kill(false){}
	virtual ~WeakPtr(){ destroy(); }

	bool isNull() const{ return d == NULL; }
	
	String getName() const{ return String("Pointer<")+typeid(ItemType).name()+">"; }

	Item * get(){ if( isNull() ) throw std::logic_error( getName()+" is invalid !" ); return d; }
	const Item * get() const{ if( isNull() ) throw std::logic_error( getName()+" is invalid !" ); return d; }
	
	Item * operator* (){ return get(); }
	const Item * operator*() const{ return get(); }

	Item * operator->(){ return get(); }
	const Item * operator->() const{ return get(); }
	
	WeakPtr<Item>& operator=( WeakPtr<Item>& rk ){ return swap( rk ); }
	WeakPtr<Item>& operator=( Item* rk ){ return swap( rk ); }

	WeakPtr<Item>& swap( WeakPtr<Item>& rk ){Item* tmp(d); d = rk.d; rk.d = tmp; kill = false; return *this; }
	WeakPtr<Item>& swap( Item* rk ){ Item* tmp(d); d = rk; rk = tmp; kill = false; return *this; }

	operator bool() const{ return !isNull(); }
	bool operator == ( const WeakPtr<Item>& rk ) const{ return d == rk.d; }
	bool operator != ( const WeakPtr<Item>& rk ) const{ return d != rk.d; }

	void destroy( bool force_kill = false ){ 
		if( !isNull() && (force_kill||kill) ){			
			#if defined(_DEBUG)||!defined(NDEBUG)
					QEnvStatus::addMessage( "Destroying "+getName(), true );
			#endif
			delete d; d = NULL; 
		}
	}
	void setDestroy( bool dest ){ kill = dest; }
	bool shouldDestroy() const{ return kill; }

	operator std::string() const{ return getName().toStdString(); }
	operator QString() const{ return getName().toStdString(); }
};

#endif